export type Cmd = {
    cmd: string,
    params: unknown,
    call: (cmd: string, params: unknown, dt: number) => void
}

/**
 * 任务队列
 */
export class TaskQueueTool {
    // 步进帧数
    static readonly PerStep = 5

    private _CmdList: Cmd[]
    private _cmd: Cmd
    private _lastStepTime: number
    private _stepCtn: number

    /**
     * 初始化任务队列
     * @param perStep 步进间隔帧数，默认值3，每3帧执行一次任务
     */
    constructor(perStep: number = TaskQueueTool.PerStep) {
        cc.log(`${cc.js.getClassName(this)} constructor`)

        this._stepCtn = perStep
    }

    /**
     * 添加命令任务
     * @param cmd 命令对象 cmd = {
                                        cmd: Number,
                                        params: Object,
                                        call: Function,
                                    }
     * @param immediately 是否立刻执行，默认false异步队列执行（每帧一步）
     * @param clearOldCmd 是否清理旧命令
     * @example
     * this._ctrl.addCmd({
            cmd: Const.HallView.Cmd.RegistCpntUpdateWithName,
            params: {},
            call: (cmd, params) => {
                // ....
                this._ctrl.doneCmd(cmd)
            },
        })
     */
    addCmd(cmd: Cmd, immediately: boolean = false, clearOldCmd: boolean = true): void {
        // cc.log(`${cc.js.getClassName(this)} addCmd ${cmd.cmd} immediately = ${immediately}`)

        this._CmdList = this._CmdList || []
        if (cmd) {
            if (cmd.cmd) {
                this._lastStepTime = this._lastStepTime || Date.now()
                if (immediately) {
                    this.doCmd(cmd)
                } else {
                    if (clearOldCmd) {
                        for (let index = 0; index < this._CmdList.length; index++) {
                            let localCmd = this._CmdList[index]
                            if (cmd.cmd === localCmd.cmd) {
                                this._CmdList.splice(index, 1)
    
                                break
                            }
                        }
                    }
                    this._CmdList.push(cmd)
                }
            } else {
                cc.error(`${cc.js.getClassName(this)} The cmd.cmd "${cmd.cmd}" you send is unknown!`)
            }
        }
    }

    /**
     * 执行命令任务
     * @param immediatelyCmd 传入则立刻执行
     */
    doCmd(immediatelyCmd: Cmd = null): void {
        this._stepCtn--
        if (this._stepCtn === 0 || immediatelyCmd) {
            this._stepCtn = TaskQueueTool.PerStep
            let dt: number = Date.now() - this._lastStepTime
            if (immediatelyCmd) {
                // cc.log(`${cc.js.getClassName(this)} doCmd ${immediatelyCmd.cmd}`)
    
                this._cmd = immediatelyCmd
                immediatelyCmd.call(immediatelyCmd.cmd, immediatelyCmd.params, 0)
            } else {
                this._CmdList = this._CmdList || []
                this._cmd = this._cmd || this._CmdList.shift()
                if (this._cmd) {
                    // cc.log(`${cc.js.getClassName(this)} doCmd ${this._cmd.cmd}`)
    
                    this._cmd.call(this._cmd.cmd, this._cmd.params, dt)
                }
            }
        }
    }

    /**
     * 完成一次任务命令后回调，以便开始下一个命令任务
     */
    doneCmd(cmd: string): void {
        // cc.log(`${cc.js.getClassName(this)} doneCmd ${cmd}`)

        if (this._cmd && cmd === this._cmd.cmd) {
            this._cmd = null
        }
    }

    /**
     * 清理所有
     */
    clear() {
        // cc.log(`${cc.js.getClassName(this)} clear`)

        this._cmd = null
        this._CmdList = []
    }
}